package com.yihaodian.search.code.service.impl;

import java.sql.Date;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.yihaodian.api.client.SearchClient;
import com.yihaodian.api.search.SearchRequest;
import com.yihaodian.api.search.SearchResponse;
import com.yihaodian.api.search.facet.SearchFacetSpec;
import com.yihaodian.api.search.highlight.HighlightSpec;
import com.yihaodian.api.search.misc.SearchHit;
import com.yihaodian.api.search.misc.SearchSort;
import com.yihaodian.api.search.misc.SearchSortField;
import com.yihaodian.api.search.query.BooleanQuery;
import com.yihaodian.api.search.query.BooleanQuery.BooleanClause.Occur;
import com.yihaodian.api.search.query.Query;
import com.yihaodian.api.search.query.TermQuery;
import com.yihaodian.search.code.model.Attribute;
import com.yihaodian.search.code.model.CodeSearchRequest;
import com.yihaodian.search.code.model.Item;
import com.yihaodian.search.code.model.SearchResult;
import com.yihaodian.search.code.model.SourceHit;
import com.yihaodian.search.code.service.SearchCodeService;
import com.yihaodian.search.code.service.SourceIndexService;

public class SearchCodeServiceImpl implements SearchCodeService {
	SearchClient client = new SearchClient();

	@Override
	public SearchResult search(CodeSearchRequest request) {
		SearchResponse response = client
				.search(convertToSearchRequest(request));

		return convertToResult(request, response);
	}

	@Override
	public SourceHit fetchSource(String id) {
		Query query = new TermQuery("id", id);
		SearchRequest searchRequest = new SearchRequest(
				SourceIndexService.INDEX_NAME, query);
		SearchResponse response = client.search(searchRequest);
		SourceHit hit = new SourceHit();
		hit.setContent(response.getHits()[0].getFieldValues().get("content")
				.replace("\r\n", "<br>").replace("\n", "<br>"));
		return hit;
	}

	private SearchRequest convertToSearchRequest(CodeSearchRequest request) {
		Query query = getQuery(request);
		SearchRequest searchRequest = new SearchRequest(
				SourceIndexService.INDEX_NAME, query);
		searchRequest.setHighlightSpecs(getHighlightSpec());

		Map<String, SearchFacetSpec> facetmap = new HashMap<String, SearchFacetSpec>();
		facetmap.put("projectName", new SearchFacetSpec());
		facetmap.put("fileType", new SearchFacetSpec());
		searchRequest.setFacetSpecMap(facetmap);

		searchRequest.setSort(getSort(request));
		
		searchRequest.setCount(SearchResult.pageSize);
		searchRequest.setOffset(request.getPageNo() * SearchResult.pageSize);
		return searchRequest;
	}

	private SearchResult convertToResult(CodeSearchRequest request,
			SearchResponse response) {
		SearchResult result = new SearchResult();
		result.setKeyword(request.getKeyword());

		List<SourceHit> sourceList = new ArrayList<SourceHit>();
		SearchHit[] hits = response.getHits();
		SearchHit hit = null;
		SourceHit sourceHit = null;
		DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		for (int i = 0; i < hits.length; i++) {
			hit = hits[i];
			sourceHit = new SourceHit();
			// Title
			sourceHit.setTitle(
					highlightTitle(hit.getFieldValues().get("relativPath"), 
					request.getKeyword()));
			sourceHit.setUid(hit.getFieldValues().get("id"));
			// escapse content
			String fregments[] = hit.getHighlightValues().get("content");
			if (fregments != null && fregments.length > 0) {
				sourceHit.setFregment(fregments[0].replace("\r\n", "<br>")
						.replace("\n", "<br>"));
			} else {
				String content = hit.getFieldValues().get("content");
				if (content.length() > 200) {
					content = content.substring(0, 200);
				}
				sourceHit.setFregment(content);
			}
			// Get last update date
			String lastUpdateTime = format.format(new Date(Long.parseLong(
					hit.getFieldValues().get("lastUpdateTime"))));
			sourceHit.setLastUpdateTime(lastUpdateTime);

			sourceList.add(sourceHit);
		}
		result.setSources(sourceList);

		result.setFacetResults(response.getFacetResultMap());
		
		// pageInfo
		result.setCurrentPage(request.getPageNo());
		result.setTotal(response.getTotalHit());
		return result;
	}

	private Query getQuery(CodeSearchRequest request) {
		BooleanQuery booleanQuery = new BooleanQuery();
//		Query query = new TermQuery("search", request.getKeyword());
//		booleanQuery.addQuery(query, Occur.MUST);
		Query queryContent = new TermQuery("content", request.getKeyword());
		Query queryFileName = new TermQuery("fileName", request.getKeyword());
		queryFileName.setBoost(2.0);
		booleanQuery.addQuery(queryContent, Occur.SHOULD);
		booleanQuery.addQuery(queryFileName, Occur.SHOULD);

		// Project name filter
		Attribute projectAttr = request.getProjectAttr();
		if (projectAttr != null && projectAttr.getItemList().size() > 0) {
			BooleanQuery projectQuery = new BooleanQuery();
			for (Item item : projectAttr.getItemList()) {
				if (item.isChecked()) {
					TermQuery pQuery = new TermQuery("projectName",
							item.getLabel());
					projectQuery.addQuery(pQuery, Occur.SHOULD);
				}
			}
			booleanQuery.addQuery(projectQuery, Occur.MUST);
		}

		// File type filter
		Attribute fileTypeAttr = request.getFileTypeAttr();
		if (fileTypeAttr != null && fileTypeAttr.getItemList().size() > 0) {
			BooleanQuery fileTypeQuery = new BooleanQuery();
			for (Item item : fileTypeAttr.getItemList()) {
				if (item.isChecked()) {
					TermQuery fQuery = new TermQuery("fileType",
							item.getLabel());
					fileTypeQuery.addQuery(fQuery, Occur.SHOULD);
				}
			}
			booleanQuery.addQuery(fileTypeQuery, Occur.MUST);
		}

		return booleanQuery;
	}

	private HighlightSpec[] getHighlightSpec() {
		HighlightSpec specContent = new HighlightSpec("content");
		specContent.setFragmentCharSize(200);
		return new HighlightSpec[] { specContent };
	}

	private SearchSort getSort(CodeSearchRequest request) {
		SearchSort sort = null;

		int sortBy = request.getSortBy();
		if (sortBy == CodeSearchRequest.SORT_LAST_UPDATE) {
			sort = new SearchSort();
			SearchSortField[] sorts = new SearchSortField[1];
			sorts[0] = new SearchSortField("lastUpdateTime", true);
			sort.setFields(sorts);
		}

		return sort;
	}
	
	private String highlightTitle(String origin, String keyword){
		int index = origin.indexOf(keyword);
		if (index == -1) {
			return origin;
		}
		
		int keywordEnd = index + keyword.length();
		StringBuilder titleBu = new StringBuilder();
		titleBu.append(origin.substring(0, index))
			.append("<span style='color: red;'>")
			.append(origin.subSequence(index, keywordEnd))
			.append("</span>")
			.append(origin.substring(keywordEnd));
		return titleBu.toString();
	}
}
